package com.cmse.persistence.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.cmse.persistence.constant.ConstantString;
import com.cmse.persistence.dao.IBaseDao;
import com.cmse.persistence.enmu.FetchOrderType;
import com.cmse.persistence.enmu.VerifyType;

/**
 * @author wulibin, exceptsky@gmail.com, 2012-3-13 下午7:08:52
 * 
 */
@SuppressWarnings("unchecked")
public class BaseDao<T> extends HibernateDaoSupport implements IBaseDao<T> {
	private static Logger          logger           = Logger.getLogger(BaseDao.class);
	
	private Class<T> persistentClass;
	private String className;
	
	public BaseDao() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
		this.className = this.persistentClass.getName();
	}

	@Override
	public void add(T entity) {
		try {
			getHibernateTemplate().save(entity);
		} catch (Exception e) {
			logger.error(e);
		}

	}

	@Override
	public void addBatch(List<T> entityList) {
		try {
			for (T entity : entityList) {
				getHibernateTemplate().save(entity);
			}
		} catch (Exception e) {
			logger.error(e);
		}
	}

	@Override
	public boolean delete(long id) {
		try {
			T entity = get(id);
			if (entity != null) {
				getHibernateTemplate().delete(entity);
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			logger.error(e);
			return false;
		}
	}

	@Override
	public List<Long> deleteBatch(long ids[]) {
		List<Long> failIds = new ArrayList<Long>();
		for (long id : ids) {
			boolean result = this.delete(id);
			if (false == result) {
				failIds.add(new Long(id));
			}
		}
		return failIds;
	}

	@Override
	public T get(long id) {
		try {
			return (T) getHibernateTemplate().get(getPersistentClass(), id);
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
	}

	@Override
	public List<T> getBatch(long[] ids) {
		List<T> entries = new ArrayList<T>();
		for (long id : ids) {
			entries.add(this.get(id));
		}
		return entries;
	}

	@Override
	public void update(T entity) {
		try {
			getHibernateTemplate().update(entity);
		} catch (Exception e) {
			logger.error(e);
		}
	}

	@Override
	public void updateBatch(List<T> entityList) {
		for (T o : entityList) {
			this.update(o);
		}
	}

	@Override
	public long getTotalCount() {
		try {
			long count = (Long) getHibernateTemplate().execute(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							String hql = "select count(c.id) from " + className+ " as c ";
							return session.createQuery(hql).uniqueResult();
						}
					});
			return count;
		} catch (Exception e) {
			logger.error(e);
			return 0l;
		}

	}

	@Override
	public List<T> getPage(int offset, int length, FetchOrderType orderType) {
		String hql = "from "+className+" as c";
		hql += getOrderSql("c", orderType);
		
		try {
			return selectByPage(hql, null, offset, length);
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
		
	}
	
	public List<T> getAll(FetchOrderType orderType) {
		try {
			return (List<T>)this.getHibernateTemplate().find("from "+className+" as c"+getOrderSql("c", orderType));
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
		
	}

	@Override
	public long getCountByCondition(final T expEntity) {
		try {
			long count = (Long)getHibernateTemplate().execute(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							Example example =Example.create(expEntity);
							Criteria criteria = session.createCriteria(getPersistentClass());
							return criteria.add(example).setProjection(Projections.rowCount()).uniqueResult();
						}
					});
			return count;
		} catch (Exception e) {
			logger.error(e);
			return 0l;
		}
	}

	@Override
	public List<T> getByCondition(final T expEntity, final int offset, final int length, final FetchOrderType orderType) {
		try {
			List<T> result = getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							
							Example example =Example.create(expEntity).ignoreCase();
							Criteria criteria = session.createCriteria(getPersistentClass());
							criteria.add(example)
							.setFirstResult(offset)
							.setMaxResults(length);
							
							if(null != orderType){
						        if(orderType.getMethod().equalsIgnoreCase(ConstantString.DESC)){
						        	criteria.addOrder(Order.desc(orderType.getKey()));
						        }else if(orderType.getMethod().equalsIgnoreCase(ConstantString.ASC)){
						        	criteria.addOrder(Order.asc(orderType.getKey()));
						        }
							}
							return criteria.list();
						}
					});
			return result;
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
	}
	
	/*
	 * 分页查找数据
	 */
	protected List<T> selectByPage(final String hql, final Object[] params,
			final int offset, final int length) {
		try {
			List<T> list = getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							Query query = session.createQuery(hql);
							if (null != params) {
								for (int i = 0; i < params.length; i++) {
									query.setParameter(i, params[i]);
								}
							}
							query.setFirstResult(offset);
							query.setMaxResults(length);
							return query.list();
						}
					});
			return list;
		} catch (Exception e) {
			logger.error(e);
			return null;
		}
	}

	/*
	 * 获取排序字符串。如：order by a.createdAt desc
	 */
	protected String getOrderSql(String tableName, FetchOrderType orderType) {
		if(null != orderType){
			orderType = FetchOrderType.CREATE_DESC;
		}
		return " order  by " + tableName + "." + orderType.getKey() + " "+ orderType.getMethod();
	}
	
	protected String getVerifySql(String tableName, VerifyType verifyType) {
		if(verifyType == VerifyType.ALL){
			return "";
		}
		String sql = " ";
		if(null!=tableName && tableName.length() !=0){
			sql += tableName+".";
		}
		if(verifyType== VerifyType.VERIFY){
			sql += "verified=true";
		}else if(verifyType== VerifyType.UNVERIFY){
			sql += "verified=false";
		}
		return sql;
	}
	
	private Class<T> getPersistentClass() {
		return this.persistentClass;
	}
}
